home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Magazine / Online / QMail / source / spawn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-15  |  6.4 KB  |  260 lines

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include "sig.h"
  4. #include "wait.h"
  5. #include "substdio.h"
  6. #include "byte.h"
  7. #include "str.h"
  8. #include "stralloc.h"
  9. #include "select.h"
  10. #include "exit.h"
  11. #include "coe.h"
  12. #include "open.h"
  13. #include "error.h"
  14. #include "auto_qmail.h"
  15. #include "auto_uids.h"
  16. #include "auto_spawn.h"
  17.  
  18. extern int truncreport;
  19. extern int spawn();
  20. extern void report();
  21. extern void initialize();
  22.  
  23. struct delivery
  24.  {
  25.   int used;
  26.   int fdin; /* pipe input */
  27.   int pid; /* zero if child is dead */
  28.   int wstat; /* if !pid: status of child */
  29.   int fdout; /* pipe output, -1 if !pid; delays eof until after death */
  30.   stralloc output;
  31.  }
  32. ;
  33.  
  34. struct delivery *d;
  35.  
  36. void sigchld()
  37. {
  38.  int wstat;
  39.  int pid;
  40.  int i;
  41.  while ((pid = wait_nohang(&wstat)) > 0)
  42.    for (i = 0;i < auto_spawn;++i) if (d[i].used)
  43.      if (d[i].pid == pid)
  44.       {
  45.        close(d[i].fdout); d[i].fdout = -1;
  46.        d[i].wstat = wstat; d[i].pid = 0;
  47.       }
  48. }
  49.  
  50. int flagwriting = 1;
  51.  
  52. int okwrite(fd,buf,n) int fd; char *buf; int n;
  53. {
  54.  int w;
  55.  if (!flagwriting) return n;
  56.  w = write(fd,buf,n);
  57.  if (w != -1) return w;
  58.  if (errno == error_intr) return -1;
  59.  flagwriting = 0; close(fd);
  60.  return n;
  61. }
  62.  
  63. int flagreading = 1;
  64. char outbuf[1024]; substdio ssout;
  65.  
  66. int stage = 0; /* reading 0:delnum 1:messid 2:sender 3:recip */
  67. int flagabort = 0; /* if 1, everything except delnum is garbage */
  68. int delnum;
  69. stralloc messid = {0};
  70. stralloc sender = {0};
  71. stralloc recip = {0};
  72.  
  73. void err(s) char *s;
  74. {
  75.  char ch; ch = delnum; substdio_put(&ssout,&ch,1);
  76.  substdio_puts(&ssout,s); substdio_putflush(&ssout,"",1);
  77. }
  78.  
  79. void docmd()
  80. {
  81.  int f;
  82.  int i;
  83.  int j;
  84.  int fdmess;
  85.  int pi[2];
  86.  struct stat st;
  87.  
  88.  if (flagabort) { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; }
  89.  if (delnum < 0) { err("ZInternal error: delnum negative. (#4.3.5)\n"); return; }
  90.  if (delnum >= auto_spawn) { err("ZInternal error: delnum too big. (#4.3.5)\n"); return; }
  91.  if (d[delnum].used) { err("ZInternal error: delnum in use. (#4.3.5)\n"); return; }
  92.  for (i = 0;i < messid.len;++i)
  93.    if (messid.s[i])
  94.      if (!i || (messid.s[i] != '/'))
  95.        if ((unsigned char) (messid.s[i] - '0') > 9)
  96.         { err("DInternal error: messid has nonnumerics. (#5.3.5)\n"); return; }
  97.  if (messid.len > 100) { err("DInternal error: messid too long. (#5.3.5)\n"); return; }
  98.  if (!messid.s[0]) { err("DInternal error: messid too short. (#5.3.5)\n"); return; }
  99.  
  100.  if (!stralloc_copys(&d[delnum].output,""))
  101.   { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; }
  102.  
  103.  j = byte_rchr(recip.s,recip.len,'@');
  104.  if (j >= recip.len) { err("DSorry, address must include host name. (#5.1.3)\n"); return; }
  105.  
  106.  fdmess = open_read(messid.s);
  107.  if (fdmess == -1) { err("Zqmail-spawn unable to open message. (#4.3.0)\n"); return; }
  108.  
  109.  if (fstat(fdmess,&st) == -1)
  110.   { close(fdmess); err("Zqmail-spawn unable to fstat message. (#4.3.0)\n"); return; }
  111.  if ((st.st_mode & S_IFMT) != S_IFREG)
  112.   { close(fdmess); err("ZSorry, message has wrong type. (#4.3.5)\n"); return; }
  113.  if (st.st_uid != auto_uidq) /* aaack! qmailq has to be trusted! */
  114.   /* your security is already toast at this point. damage control... */
  115.   { close(fdmess); err("ZSorry, message has wrong owner. (#4.3.5)\n"); return; }
  116.  
  117.  if (pipe(pi) == -1)
  118.   { close(fdmess); err("Zqmail-spawn unable to create pipe. (#4.3.0)\n"); return; }
  119.  
  120.  coe(pi[0]);
  121.  
  122.  f = spawn(fdmess,pi[1],sender.s,recip.s,j);
  123.  close(fdmess);
  124.  if (f == -1)
  125.   { close(pi[0]); close(pi[1]); err("Zqmail-spawn unable to fork. (#4.3.0)\n"); return; }
  126.  
  127.  d[delnum].fdin = pi[0];
  128.  d[delnum].fdout = pi[1]; coe(pi[1]);
  129.  d[delnum].pid = f;
  130.  d[delnum].used = 1;
  131. }
  132.  
  133. char cmdbuf[1024];
  134.  
  135. void getcmd()
  136. {
  137.  int i;
  138.  int r;
  139.  char ch;
  140.  
  141.  r = read(0,cmdbuf,sizeof(cmdbuf));
  142.  if (r == 0)
  143.   { flagreading = 0; return; }
  144.  if (r == -1)
  145.   {
  146.    if (errno != error_intr)
  147.      flagreading = 0;
  148.    return;
  149.   }
  150.  
  151.  for (i = 0;i < r;++i)
  152.   {
  153.    ch = cmdbuf[i];
  154.    switch(stage)
  155.     {
  156.      case 0:
  157.        delnum = (unsigned int) (unsigned char) ch;
  158.        messid.len = 0; stage = 1; break;
  159.      case 1:
  160.        if (!stralloc_append(&messid,&ch)) flagabort = 1;
  161.        if (ch) break;
  162.        sender.len = 0; stage = 2; break;
  163.      case 2:
  164.        if (!stralloc_append(&sender,&ch)) flagabort = 1;
  165.        if (ch) break;
  166.        recip.len = 0; stage = 3; break;
  167.      case 3:
  168.        if (!stralloc_append(&recip,&ch)) flagabort = 1;
  169.        if (ch) break;
  170.        docmd();
  171.        flagabort = 0; stage = 0; break;
  172.     }
  173.   }
  174. }
  175.  
  176. char inbuf[128];
  177.  
  178. void main(argc,argv)
  179. int argc;
  180. char **argv;
  181. {
  182.  char ch;
  183.  int i;
  184.  int r;
  185.  fd_set rfds;
  186.  int nfds;
  187.  
  188.  if (chdir(auto_qmail) == -1) _exit(111);
  189.  if (chdir("queue/mess") == -1) _exit(111);
  190.  if (!stralloc_copys(&messid,"")) _exit(111);
  191.  if (!stralloc_copys(&sender,"")) _exit(111);
  192.  if (!stralloc_copys(&recip,"")) _exit(111);
  193.  
  194.  d = (struct delivery *) alloc((auto_spawn + 10) * sizeof(struct delivery));
  195.  if (!d) _exit(111);
  196.  
  197.  substdio_fdbuf(&ssout,okwrite,1,outbuf,sizeof(outbuf));
  198.  
  199.  sig_pipeignore();
  200.  sig_childcatch(sigchld);
  201.  
  202.  initialize(argc,argv);
  203.  
  204.  ch = auto_spawn; substdio_putflush(&ssout,&ch,1);
  205.  
  206.  for (i = 0;i < auto_spawn;++i) { d[i].used = 0; d[i].output.s = 0; }
  207.  
  208.  for (;;)
  209.   {
  210.    if (!flagreading)
  211.     {
  212.      for (i = 0;i < auto_spawn;++i) if (d[i].used) break;
  213.      if (i >= auto_spawn) _exit(0);
  214.     }
  215.    sig_childunblock();
  216.  
  217.    FD_ZERO(&rfds);
  218.    if (flagreading) FD_SET(0,&rfds);
  219.    nfds = 1;
  220.    for (i = 0;i < auto_spawn;++i) if (d[i].used)
  221.     { FD_SET(d[i].fdin,&rfds); if (d[i].fdin >= nfds) nfds = d[i].fdin + 1; }
  222.  
  223.    r = select(nfds,&rfds,(fd_set *) 0,(fd_set *) 0,(struct timeval *) 0);
  224.    sig_childblock();
  225.  
  226.    if (r != -1)
  227.     {
  228.      if (flagreading)
  229.        if (FD_ISSET(0,&rfds))
  230.      getcmd();
  231.      for (i = 0;i < auto_spawn;++i) if (d[i].used)
  232.        if (FD_ISSET(d[i].fdin,&rfds))
  233.     {
  234.      r = read(d[i].fdin,inbuf,128);
  235.      if (r == -1)
  236.        continue; /* read error on a readable pipe? be serious */
  237.      if (r == 0)
  238.       {
  239.            ch = i; substdio_put(&ssout,&ch,1);
  240.        report(&ssout,d[i].wstat,d[i].output.s,d[i].output.len);
  241.        substdio_put(&ssout,"",1);
  242.        substdio_flush(&ssout);
  243.        close(d[i].fdin); d[i].used = 0;
  244.        continue;
  245.       }
  246.      while (!stralloc_readyplus(&d[i].output,r)) sleep(10); /*XXX*/
  247.      byte_copy(d[i].output.s + d[i].output.len,r,inbuf);
  248.      d[i].output.len += r;
  249.      if (truncreport > 100)
  250.        if (d[i].output.len > truncreport)
  251.         {
  252.          char *truncmess = "\nError report too long, sorry.\n";
  253.          d[i].output.len = truncreport - str_len(truncmess) - 3;
  254.          stralloc_cats(&d[i].output,truncmess);
  255.         }
  256.     }
  257.     }
  258.   }
  259. }
  260.